package org.zoomdev.zoom.dao.impl;

import org.zoomdev.zoom.aop.Constructor;
import org.zoomdev.zoom.aop.factory.ConstructorFactory;
import org.zoomdev.zoom.common.exceptions.ZoomException;
import org.zoomdev.zoom.dao.Dao;
import org.zoomdev.zoom.dao.Entity;
import org.zoomdev.zoom.dao.adapters.EntityField;
import org.zoomdev.zoom.dao.adapters.ResultSetAdapter;
import org.zoomdev.zoom.dao.annotations.Join;
import org.zoomdev.zoom.dao.annotations.Link;
import org.zoomdev.zoom.dao.struct.ColumnMeta;
import org.zoomdev.zoom.dao.struct.JoinMeta;
import org.zoomdev.zoom.dao.struct.TableMeta;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.LinkedHashSet;
import java.util.Set;

public class BeanEntity implements Entity {

    private final String tableName;
    private final EntityField[] entityFields;

    private final Constructor constructor;
    private final TableMeta tableMeta;

    private final EntityField[] primaryKeys;

    private final Set<TableMeta> tables = new LinkedHashSet<>();


    private final JoinMeta[] joinMetas;

    private final Dao dao;
    private final Class<?> type;

    public BeanEntity(Class<?> type, Dao dao, TableMeta tableName, EntityField[] primaryKeys, EntityField[] entityFields) {
        this.tableName = tableName.getName();
        this.type = type;
        this.entityFields = entityFields;
        this.primaryKeys = primaryKeys;
        this.tableMeta = tableName;
        this.constructor = ConstructorFactory.FACTORY.create(type);
        if (this.constructor == null) {
            throw new ZoomException("找不到无参构造函数" + type);
        }
        this.dao = dao;

        for (EntityField field : entityFields) {
            tables.add(field.getColumnMeta().getTableMeta());
        }

        Link link = type.getAnnotation(Link.class);
        if (link != null) {
            Join[] joins = link.value();
            joinMetas = getJoinConfigs(joins);
        } else {
            joinMetas = null;
        }
    }


    private JoinMeta[] getJoinConfigs(Join[] joins) {
        if (joins == null) return null;
        JoinMeta[] joinMetas = new JoinMeta[joins.length];
        for (int i = 0; i < joins.length; ++i) {
            Join join = joins[i];
            //
            JoinMeta joinMeta = new JoinMeta();
            joinMeta.setOn(join.on());
            joinMeta.setTable(join.table());
            joinMeta.setType(join.type());

            joinMetas[i] = joinMeta;
        }
        return joinMetas;
    }

    @Override
    public JoinMeta[] getJoinMetas() {
        return joinMetas;
    }

    @Override
    public int getTableCount() {
        return tables.size();
    }


    public EntityField tryToFind(String field) {
        for (EntityField entityField : entityFields) {
            if (field.equalsIgnoreCase(entityField.getFieldName())) {
                return entityField;
            }
            if (field.equalsIgnoreCase(entityField.getColumn())) {
                return entityField;
            }
            ColumnMeta meta = entityField.getColumnMeta();
            if (meta != null) {
                if (field.equalsIgnoreCase(meta.getName())) {
                    return entityField;
                }
            }

        }
        return null;
    }

    public TableMeta getTableMeta() {
        return tableMeta;
    }

    @Override
    public Object fromResultSet(ResultSet rs, EntityField[] entityFields) {
        try {
            Object data = constructor.newInstance();
            int index = 1;

            ResultSetMetaData meta = rs.getMetaData();
            int columnCount = meta.getColumnCount();
            String[] labelNames = new String[columnCount + 1];
            String[] tableNames = new String[columnCount + 1];
            int[] types = new int[columnCount + 1];
            for (int i = 1; i < labelNames.length; i++) {
                tableNames[i] = meta.getTableName(i);
                labelNames[i] = meta.getColumnLabel(i);
                types[i] = meta.getColumnType(i);
            }

            System.out.println("yes");


            if (entityFields == null) {


            } else {
                for (EntityField field : entityFields) {
                    ResultSetAdapter resultSetAdapter = field.getResultSetAdapter();
                    Object value = resultSetAdapter.getObject(rs, index++);
                    field.set(data, value);
                }
            }
            return data;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public int[] generateKeys() {
        return new int[0];
    }

    @Override
    public void parseGenerateKeys(ResultSet rs) {


    }

    @Override
    public String getTableName() {
        return tableName;
    }

    @Override
    public EntityField[] getEntityFields() {
        return entityFields;
    }

    @Override
    public EntityField[] getPrimaryKeys() {
        return primaryKeys;
    }


    @Override
    public Object newInstance() {
        return constructor.newInstance();
    }

    @Override
    public Entity addTable(String table) {
        return dao.entity(type, table);
    }


}
